﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Joins;
using System.Reactive.Linq;
using System.Reactive.PlatformServices;
using System.Reactive.Subjects;
using System.Reactive.Threading;
using System.Reactive.Threading.Tasks;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

using agree;
using agree.itsdb;
using agree.schema;
using agree.composition;

using alib.Concurrency;
using alib.Debugging;
using alib.Enumerable;
using alib.Int;
using alib.String;
using alib.String.Builder;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class f_console : f_primitive<IChartControl, IChartControl>
	{


		public f_console(IRtParent parent)
			: base(parent)
		{
		}

		void setup()
		{
			cd = new ColDefs();

			cx_hdr = cd.hdra.Length;

			cur_line = 0;
			y_window = Console.CursorTop;

			gen_base = GC.CollectionCount(2);
		}

		public ColDefs cd;

		public int cx_hdr;
		int index;
		int cur_line;
		int y_window;
		public int gen_base;
		const int MIN_TRIM = 5;
		const int id_width = 4;

		protected override IChartControl func(IChartControl _ctrl)
		{
			if (cx_hdr == 0)
				setup();

			var ctrl = (ParseControl)_ctrl;
			var item = ctrl.SourceItem;

#if true
			Object tmp;
			int ix;
			if ((tmp = PP.ItemIndex.GetValue(item)) is int)
				ix = (int)tmp;
			else
				PP.ItemIndex.SetValue(item, ix = index++);

			int id = (tmp = PP.ExternalId.GetValue(item)) is int ? (int)tmp : 0;

			String report;
			int trim_val = Math.Max(MIN_TRIM, cd.bw - (5 + id_width) - cx_hdr);

			String s_item = item.Text;

			s_item = s_item.SubstringOrLess(0, trim_val);

			report = String.Format("{0,3:##0} {1," + id_width + "} $yellow {2}", ix, id, s_item);

			report += String.Format(new String(' ', Math.Max(0, cd.bw - (5 + id_width) - cx_hdr - s_item.Length)));

			int cx, cy;
			lock (Console.Out)
			{
				cy = cur_line++;
				Console.SetCursorPosition(0, y_window + cy);
				Console.Out.WriteColor(report);
				cx = Console.CursorLeft;
			}

			if (ctrl.IsCompleted)
				finish_item(cx, cy, ctrl, item);
			else
				((INotifyCompletion)ctrl).OnCompleted(() => finish_item(cx, cy, ctrl, item));
#endif
			return ctrl;
		}


		void finish_item(int cx, int cy, ParseControl ctrl, IString item)
		{
			lock (Console.Out)
			{
				Console.SetCursorPosition(cx, y_window + cy);

				cd.Update(this, y_window + cy, ctrl, item);
			}
		}
	};

}

#if false
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class ParseSession : _monad<IActiveObj<IRootDerivation>>, IMonad<IActiveObj<IRootDerivation>, IUnit>, IDisposable
{
	int q = 0;
	MainClass mc;
	Tfs.MonospaceFormatter mf = null;
	//String fdate;
	Grammar g;

	int id_width;
	TimingReport tr;

	int c_unif_tot = 0;
	long ms_tot = 0;

	HashSet<Edge.Flag> filter_preds;

	const int MIN_TRIM = 5;
	TimingReport tr;
	public void Dispose() { tr.Dispose(); }

	StreamWriter train_features_stream;

	public System.Type[] Targs { get { return alib.Reflection.TypeTuples<IActiveObj<IRootDerivation>, IUnit>.Targs; } }

	public override object ProvideValue(IServiceProvider serviceProvider)
	{
		Debug.Assert(t0.Trace != null);
		var item = this.FindTrace<IString>();

		int ix = (int)P.ItemIndex.GetValue(item);

		this.Report(item, ix, t0);
		//ps.ParseResultHandler(item, ix, ctrl);
		return agree.composition.f_unit.Instance;
	}


	public ParseSession(MainClass mc, Grammar g, StreamWriter sw_feats)
		: base(null)
	{
		this.mc = mc;
		this.g = g;
		this.id_width = 4;
		this.train_features_stream = sw_feats;

		this.filter_preds = new HashSet<Edge.Flag>();
		this.filter_preds.Add(g.td["parg_d_rel"].EdgeFlag);
		this.filter_preds.Add(g.td["focus_d_rel"].EdgeFlag);

		tr = new TimingReport(Console.Out, "Parsing...");


	}


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	IRootDerivation[] GetItemDetailReport(StringBuilder report, IString item, IActiveObj<IRootDerivation> act_deriv)
	{
		IRootDerivation[] rg_deriv = null;
		IDerivation a_best = null;
		try
		{
			Stats stats;
			String problems = "";

			ParseControl ctrl = act_deriv.FindTrace<ParseControl>();
			if (ctrl == null)
				throw new Exception();
			rg_deriv = act_deriv.ToArray().First();

			var qx = rg_deriv[0].DescendantsAndSelf.ToArray();
			Nop.X();
			{
				//if (mc.f_gen)
				{
					//a_best = ctrl.chart.ValidatedRootDerivations.LastOrDefault();

					//if (a_best != null)
					//Tfs tfs = a_best.Tfs;
					//if (tfs == null)
					//    Nop.X();
					////Console.WriteLine(a_best.ReadBack.StringJoin(" "));
					//if (mrs == null)
					//    Nop.X();
					rg_deriv = ctrl.ValidatedRootDerivations.ToArray().First();// a_best.Tfs.Mrs;

					//if (rg_deriv.Length == 0)
					//    rg_deriv = ctrl.chart.ValidatedRootDerivations.ToArray();// a_best.Tfs.Mrs;
				}
				//else
				//{
				//	a_best = null;// rg_deriv.FirstOrDefault();
				//}
				stats = ctrl.stats;
				stats.Disconnect();
			}


			int c_derivations = rg_deriv.Length;// stats.Parsing.Chart.Unpacking.c_derivations;

			int c_exp = (int)P.ExpectedDerivationCount.GetValue(item);

			if (c_exp != c_derivations)
			{
				problems += String.Format("error: $red derivations {0}$ , expected {1}", c_derivations, c_exp);
				problems += Environment.NewLine;
			}

			Double mem = (Double)Process.GetCurrentProcess().PrivateMemorySize64 / (1024 * 1024 * 1024);
			String gcinfo = String.Format("{0}", GC.CollectionCount(2) - gen_base);

			//  read  wall   unif. %t unif. ok  lx  ana %t  unif. QC    pas    act   cmp   eq  fwd  rev %t  unif.   GB GC
			String rxt =
				String.Format("$magenta {0,6:G}$ {1,6:#.###} $green {2,7:G}$ $DarkRed {3,2}$ $green {4,5:G}$ {5,2} {6,3:G} {7,4:G} $DarkRed {8,2}$ {9,2}$green {10,7:G}$ {11,2} {12,6:G} {13,6:G} {14,5:G}{15,5:G}{16,5:G}{17,5:G} $DarkRed {18,2}$ $green {19,6:G}$ {20:#.##} {21,2}",
				c_derivations,
				stats.Totals.sec_time,
				stats.Totals.Unification.c_attempted,
				_PCT(stats.Morphology.TimeRatio),
				stats.Morphology.Unification.c_attempted,
				_PCT(stats.Morphology.Unification.SuccessRatio),
				stats.Morphology.c_tokens_in,
				stats.Morphology.c_morph_objs_to_chart,
				_PCT(0),//stats.Parsing.Chart.TimeRatio),
				_PCT(stats.Parsing.Chart.Unification.QuickCheck.PercentAvoided),
				stats.Parsing.Chart.Unification.c_attempted,
				_PCT(stats.Parsing.Chart.Unification.SuccessRatio),
				stats.Parsing.Chart.c_passive_edges,
				stats.Parsing.Chart.c_active_edges,
				stats.Parsing.Chart.c_root_edges,
				stats.Parsing.Chart.Packing.c_equivalence,
				stats.Parsing.Chart.Packing.c_proactive,
				stats.Parsing.Chart.Packing.c_retroactive,
				_PCT(0),//stats.Parsing.Chart.Unpacking.TimeRatio),
				stats.Parsing.Chart.Unpacking.Unification.c_attempted,
				mem.ToString("#.##").TrimEndOrPadLeft(4),
				gcinfo);

			report.AppendLine(rxt);
			report.AppendLine(problems);
		}
		catch (Exception ex)
		{
			if (ex is AggregateException)
				ex = ((AggregateException)ex).Flatten().InnerExceptions.FirstOrDefault(x => !(x is AggregateException)) ?? ex;

			report.AppendFormatLine("\r\n$red {0}: {1}$ \r\n", ex.GetType().Name, ex.Message);
			if (!(ex is ParseException))
			{
				report.AppendLine(ex.StackTrace);
				lock (Console.Out)
				{
					Console.Out.WriteLineColor(report.ToString());
					Console.ResetColor();
					Console.Out.Flush();
				}
				throw ex;
			}
		}
		return rg_deriv;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	IRootDerivation[] Report(IString item, int ix, IActiveObj<IRootDerivation> tpc)
	{
		IRootDerivation[] rg_deriv = null;
		StringBuilder report = new StringBuilder();
		int trim_val = Math.Max(MIN_TRIM, bw - (5 + id_width) - hdr_a.Length);
		String ds = ((IString)item).Text.SubstringOrLess(0, trim_val);
		report.AppendFormat("{0,3:##0} {1," + id_width + "} $yellow {2}", ix, item.Id, ds);

		report.Append(new String(' ', Math.Max(0, bw - (5 + id_width) - hdr_a.Length - ds.Length)));
		rg_deriv = GetItemDetailReport(report, item, tpc);

		var qs = report.ToString();
		if (qs.IndexOfAny(alib.Character.Charset.cr_lf) != -1)
		{
			var qq = qs.Split(alib.Character.Charset.cr_lf, StringSplitOptions.RemoveEmptyEntries);
			Monitor.Enter(Console.Out);
			foreach (string lll in qq)
				alib.Debugging._debugging_ext.ConsoleWriteLineColorNoSync(lll);
			Monitor.Exit(Console.Out);
		}
		else
			Console.Out.WriteLineColor(qs);
		return rg_deriv;
	}



	//////////////////////////////// PASSIVE ////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	//////////////////////////////// PASSIVE ////////////////////////////////
	void passive_display(GenControl genctrl)
	{
		GenControl.ChartCell[] rgcc = ((GenControl)genctrl)._debug_use;

		Console.Write("{0,-20}", "PASSIVE #rels:");
		for (int ix = 0; ix < rgcc.Length; ix++)
			if (ix == 0)
				Console.Write("   0 ");
			else
				Console.Write("{0,7} ", ix);
		Console.WriteLine();

		Console.WriteLine(new String(' ', 20) + Enumerable.Repeat("-------", rgcc.Length).StringJoin(" "));

		ulong msk = 1;
		for (int ix = 0; ix < genctrl.input.RelSlots.Length; ix++)
		{
			var rel = genctrl.input.RelSlots[ix];

			Console.Out.WriteColor("{0} $yellow {1,-18}", (Char)('a' + ix), rel[genctrl.input.mrsm.ifeat_lbl].TypeNameOrStringValue.SubstringOrLess(0, 18));

			for (int jx = 0; jx < rgcc.Length; jx++)
			{
				int mcm = 0;
				foreach (var pe in rgcc[jx])
				{
					if ((pe.ProximalContext.covered_eps & msk) != 0)
						mcm++;
				}
				Console.Write("{0,7} ", mcm);
			}
			Console.WriteLine();
			msk <<= 1;
		}
		Console.WriteLine(new String(' ', 20) + Enumerable.Repeat("-------", rgcc.Length).StringJoin(" "));

		Console.Write("{0,-20}", "passive total:");
		for (int ix = 0; ix < rgcc.Length; ix++)
			Console.Write("{0,7} ", rgcc[ix]._Count());
		Console.WriteLine();

		Console.Write("{0,-20}", "variety:");
		for (int ix = 0; ix < rgcc.Length; ix++)
			Console.Write("{0,7} ", rgcc[ix].CountDistinct(gxo => gxo.ProximalContext.covered_eps));
		Console.WriteLine();
		Console.WriteLine();
	}


	//////////////////////////////// ACTIVE ////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	//////////////////////////////// ACTIVE ////////////////////////////////
	void active_display(GenControl genctrl)
	{
		GenControl.NotificationSource[] rgns = genctrl.rgns;

		Console.Write("{0,-20}", "ACTIVE #rels:");
		for (int ix = 0; ix < rgns.Length; ix++)
			if (ix == 0)
				Console.Write("   0 ");
			else
				Console.Write("{0,7} ", ix);
		Console.WriteLine();

		Console.WriteLine(new String(' ', 20) + Enumerable.Repeat("-------", rgns.Length).StringJoin(" "));

		ulong msk = 1;
		for (int ix = 0; ix < genctrl.input.RelSlots.Length; ix++)
		{
			var rel = genctrl.input.RelSlots[ix];

			Console.Out.WriteColor("{0} $yellow {1,-18}", (Char)('a' + ix), rel[genctrl.input.mrsm.ifeat_lbl].TypeNameOrStringValue.SubstringOrLess(0, 18));

			for (int jx = 0; jx < rgns.Length; jx++)
			{
				int mcm = 0;
				foreach (GenControl.ActiveEdge ae in rgns[jx])
				{
					if ((ae.ctx.covered_eps & msk) != 0)
						mcm++;
				}
				Console.Write("{0,7} ", mcm);
			}
			Console.WriteLine();
			msk <<= 1;
		}
		Console.WriteLine(new String(' ', 20) + Enumerable.Repeat("-------", rgns.Length).StringJoin(" "));

		Console.Write("{0,-20}", "active total:");
		for (int ix = 0; ix < rgns.Length; ix++)
			Console.Write("{0,7} ", rgns[ix]._Count());
		Console.WriteLine();

		Console.Write("{0,-20}", "variety:");
		for (int ix = 0; ix < rgns.Length; ix++)
			Console.Write("{0,7} ", rgns[ix].CountDistinct(gxo => gxo.ctx.covered_eps));
		Console.WriteLine();
		Console.WriteLine();
	}


	List<String> g_results = new List<String>();

	public static string _PCT(double pct)
	{
		if (double.IsInfinity(pct))
			return "oo";
		if (double.IsNaN(pct))
			return "  ";
		if (pct < 1.0)
			return ((int)(pct * 100)).ToString();
		return "%%";
	}
};
#endif
